package com.njtoyo.taxi.admin.service.business.driver.impl;

import cn.hutool.core.util.ReUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.logic.business.driver.MoneyDeductingLogLogic;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverFlowLogCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverFlowLogInOut;
import com.njtoyo.taxi.admin.mapper.master.enums.MemberCategory;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.mongo.entity.secondary.AdminDeductDriverMoneyLogMongo;
import com.njtoyo.taxi.admin.mongo.repository.secondary.AdminDeductDriverMoneyLogMongoRepository;
import com.njtoyo.taxi.admin.rest.presenter.business.driver.MoneyDeductingPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.MoneyDeductingCreateWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.MoneyDeductingLogQueryDto;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.MoneyDeductingLogQueryWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.MoneyDeductingQueryWrapper;
import com.njtoyo.taxi.admin.service.business.driver.DriverMoneyDeductingService;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class DriverMoneyDeductingServiceImpl implements DriverMoneyDeductingService {
    @Autowired
    private DriverMapper driverMapper;

    @Autowired
    private TaxiMapper taxiMapper;

    @Autowired
    private PrimaryCachePutter primaryCachePutter;

    @Autowired
    private RideOrderMapper rideOrderMapper;

    @Autowired
    private DriverRewardMapper driverRewardMapper;

    @Autowired
    private ScanRideOrderMapper scanRideOrderMapper;

    @Autowired
    private DriverRechargeMapper driverRechargeMapper;

    @Autowired
    private StreetRideOrderMapper streetRideOrderMapper;

    @Autowired
    private CancellationOrderMapper cancellationOrder;

    @Autowired
    private DriverMoneyDeductingMapper driverMoneyDeductingMapper;

    @Autowired
    private MemberRebateMapper memberRebateMapper;

    @Autowired
    private MemberMapper memberMapper;

    @Autowired
    private SimpleCallRideOrderMapper simpleCallRideOrderMapper;

    @Autowired
    private DriverWithdrawMapper driverWithdrawMapper;

    @Autowired
    private DriverFlowLogMapper driverFlowLogMapper;

    @Autowired
    private AdminDeductDriverMoneyLogMongoRepository adminDeductDriverMoneyLogMongoRepository;

    @Autowired
    MoneyDeductingLogLogic moneyDeductingLogLogic;

    @Override
    public RestResult<Page<MoneyDeductingPresenter>> getMoneyDeductingList(AdminUser adminUser, MoneyDeductingQueryWrapper wrapper) {
        List<Driver> driverList = null;

        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
                /*driverList = new LambdaQueryChainWrapper<>(driverMapper)
                        .select(Driver::getId)
                        .in(Driver::getCantonId, identity.getCantonIds())
                        .list();*/
                wrapper.setCantonIds(identity.getCantonIds());
                break;
            case company:
                /*List<Taxi> taxiList = new LambdaQueryChainWrapper<>(taxiMapper)
                        .select(Taxi::getId)
                        .in(Taxi::getCompanyId, identity.getCompanyIds())
                        .list();

                List<Long> taxiIds = taxiList.stream().map(Taxi::getId).collect(Collectors.toList());

                driverList = new LambdaQueryChainWrapper<>(driverMapper)
                        .select(Driver::getId)
                        .in(Driver::getTaxiId, taxiIds)
                        .list();*/
                wrapper.setCompanyIds(identity.getCompanyIds());
                break;
        }

        if (Objects.nonNull(driverList)) {
            List<Long> driverIds = driverList.stream().map(Driver::getId).collect(Collectors.toList());
            wrapper.setDriverIds(driverIds);
        }

        // 司机搜索
        if (Objects.nonNull(wrapper.getDriverSearch())) {
            if (this.isPhoneNum(wrapper.getDriverSearch())) {
                wrapper.setDriverMobilePhone(wrapper.getDriverSearch());

                wrapper.setDriverSearch(null);
                wrapper.setDriverName(null);
            } else {
                wrapper.setDriverName(wrapper.getDriverSearch());

                wrapper.setDriverSearch(null);
                wrapper.setDriverMobilePhone(null);
            }
        }

        Page<MoneyDeductingPresenter> res = driverMoneyDeductingMapper.getMoneyDeductingList(wrapper);

        return RestResult.success(res);
    }

    @Override
    public RestResult<MoneyDeductingPresenter> getMoneyDeducting(Long id) {
        MoneyDeductingPresenter res = driverMoneyDeductingMapper.getMoneyDeducting(id);

        return RestResult.success(res);
    }

    @Override
    @Transactional
    public RestResult moneyDeducting(AdminUser adminUser, MoneyDeductingCreateWrapper wrapper) {
        Driver driver = driverMapper.selectById(wrapper.getDriverId());
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        if (this.computeDriverBalance(wrapper.getDriverId()).compareTo(wrapper.getDeduction()) == -1) {
            return RestResult.failed("司机账户余额不足");
        }

        DriverMoneyDeducting deduction = new DriverMoneyDeducting();
        deduction.setDriverId(wrapper.getDriverId());
        deduction.setDeduction(wrapper.getDeduction());
        deduction.setDetail(wrapper.getDetail());

        driverMoneyDeductingMapper.insert(deduction);

        DriverFlowLog driverFlowLog = new DriverFlowLog();
        driverFlowLog.setDriverId(wrapper.getDriverId());
        driverFlowLog.setAmount(wrapper.getDeduction());
        driverFlowLog.setInOut(DriverFlowLogInOut.out);
        driverFlowLog.setCategory(DriverFlowLogCategory.admin_money_deducting);
        driverFlowLog.setRefId(deduction.getId());
        driverFlowLog.setCreatedAt(new Date());

        driverFlowLogMapper.insert(driverFlowLog);

        // 清除司机缓存
        primaryCachePutter.deleteDriverTodayIncome(wrapper.getDriverId());
        primaryCachePutter.deleteDriverCacheById(wrapper.getDriverId());

        // 记录日志
        AdminDeductDriverMoneyLogMongo log = new AdminDeductDriverMoneyLogMongo();
        log.setDriver_id(driver.getId());
        log.setDriver_name(driver.getName());
        log.setDriver_mobile_number(driver.getMobileNumber());
        log.setAdmin_id(adminUser.getId());
        log.setAdmin_account(adminUser.getAccount());
        log.setAdmin_name(adminUser.getName());
        log.setAdmin_mobile_number(adminUser.getMobileNumber());
        log.setDriver_money_deducting_id(deduction.getId().intValue());
        log.setDeduction(deduction.getDeduction());
        log.setDetail(deduction.getDetail());
        long now = new Date().getTime() / 1000;
        log.setCreated_at((int) now);

        adminDeductDriverMoneyLogMongoRepository.insert(log);

        return RestResult.success();
    }

    private BigDecimal computeDriverBalance(Long driverId) {
        // 行程订单收入
        BigDecimal rideOrderIncome = rideOrderMapper.computeDriverBalance(driverId);

        // 空驶费收入
        BigDecimal rideCancellationOrderIncome = cancellationOrder.computeDriverBalance(driverId);

        // 街边收款收入
        BigDecimal streetRideOrderIncome = streetRideOrderMapper.computeDriverBalance(driverId);

        // 奖励收入
        BigDecimal rewardIncome = driverRewardMapper.computeDriverBalance(driverId);

        BigDecimal rebateIncome = BigDecimal.ZERO;

        // 返利相关
        Member member = new LambdaQueryChainWrapper<>(memberMapper)
                .eq(Member::getRefId, driverId)
                .eq(Member::getCategory, MemberCategory.driver)
                .one();

        if (Objects.nonNull(member)) {
            rebateIncome = memberRebateMapper.computeDriverBalance(member.getId());
        }

        // 扫码收款
        BigDecimal scanRideOrderIncome = scanRideOrderMapper.computeDriverBalance(driverId);

        // 一键叫车
        BigDecimal simpleCallRideOrderIncome = simpleCallRideOrderMapper.computeDriverBalance(driverId);

        // 打款
        BigDecimal withdrawAmount = driverWithdrawMapper.computeDriverBalance(driverId);

        // 平台扣款
        BigDecimal deductingAmount = driverMoneyDeductingMapper.computeDriverBalance(driverId);

        // 充值
        BigDecimal rechargeAmount = driverRechargeMapper.computeDriverBalance(driverId);

        // 行程订单收入+空驶费收入+一键叫车收入+街边收款+奖励收入+返利收入+扫码收款-提现-平台扣款-充值
        return rideOrderIncome
                .add(rideCancellationOrderIncome)
                .add(streetRideOrderIncome)
                .add(rewardIncome)
                .add(rebateIncome)
                .add(scanRideOrderIncome)
                .add(simpleCallRideOrderIncome)
                .subtract(withdrawAmount)
                .subtract(deductingAmount)
                .subtract(rechargeAmount);
    }

    @Override
    public RestResult<PageImpl<AdminDeductDriverMoneyLogMongo>> moneyDeductingLog(MoneyDeductingLogQueryWrapper queryWrapper) {
        String adminSearch = queryWrapper.getAdminSearch();
        String driverSearch = queryWrapper.getDriverSearch();

        MoneyDeductingLogQueryDto queryDto = new MoneyDeductingLogQueryDto();

        // 管理员搜索
        if (Objects.nonNull(adminSearch)) {
            if (this.isPhoneNum(adminSearch)) {
                queryDto.setAdminPhone(adminSearch);
            } else {
                queryDto.setAdminName(adminSearch);
            }
        }

        // 司机搜索
        if (Objects.nonNull(driverSearch)) {
            if (this.isPhoneNum(driverSearch)) {
                queryDto.setDriverPhone(driverSearch);
            } else {
                queryDto.setDriverName(driverSearch);
            }
        }

        queryDto.setCurrent(queryWrapper.getCurrent() - 1);
        queryDto.setSize(queryWrapper.getSize());

        PageImpl<AdminDeductDriverMoneyLogMongo> list = moneyDeductingLogLogic.getList(queryDto);

        return RestResult.success(list);
    }

    private Boolean isPhoneNum(String content) {
        return ReUtil.isMatch("^1[0-9]\\d{9}$", content);
    }
}
